import numpy as np

# TWO DIMENTIONAL VECTOR CLASS

class TwoD:
    """simple Vector class for LinAlg"""    
    
    def __init__(self, x=0, y=0):
        self.x = float(x)
        self.y = float(y)

    def __repr__(self):
        return 'TwoD(%s, %s)' % (self.x, self.y)

    def __add__(self, other):
        return TwoD(self.x + other.x, self.y + other.y)

    def __sub__(self, other):
        return TwoD(self.x - other.x, self.y - other.y)

    def __mul__(self, other):
        return TwoD(self.x * other, self.y * other)

    def __div__(self, other):
        return TwoD(self.x / other, self.y / other)

    def __iadd__(self, other):
        self.x += other.x
        self.y += other.y
        return self

    def __isub__(self, other):
        self.x -= other.x
        self.y -= other.y
        return self

    def __idiv__(self, other):
        self.x /= other
        self.y /= other
        return self

    def len(self):
        '''length of vector'''
        return ((self.x ** 2) + (self.y ** 2)) ** 0.5
    
    def set_len(self, length):
        '''set length of vector'''
        self = (self.norm()*length)
    
    def norm(self):
        if self.len() == 0: return TwoD(0,0)
        else: return self*(1./self.len())

#================Testing .....
      
class TwoDLoc(TwoD):
    """location vector with build-in modulo 
    still testing, does not work yet!!!!"""
    def __init__(self, x=0, y=0):
        self._x = float(x)
        self._y = float(y)
        #self._max_x = max_x
        #self._max_y = max_y
    def __repr__(self):
        return 'TwoDLoc(%s, %s)' % (self.x, self.y)
    def _get_x(self):
        return self._x % self._max_x
    def _get_y(self):
        return self._y % self._max_y
    def _set_x(self, x):
        self._x = x % self._max_x
    def _set_y(self, y):
        self._y = y % self._max_y
    #=======Properties======
    x = property(_get_x, _set_x)
    y = property(_get_y, _set_y)
    
#================Testing ..... END

######################### Helper Functins ##################################

def scalar(a, b):
    """scaler product vector"""
    return a.x*b.x + a.y*b.y

def angle(a, b):
    try:
        a = np.arccos(scalar(a,b)/(a.len()*b.len()))
    except:
        return 0.
    return a

def proj(a,b):
    """project a on b, return float""" #should this rather return a vector?
    try:
        p = scalar(a, b)/b.len()
    except:
        return 0
    return p


################################################################################

#class Vec:
#    """simple Vector class for LinAlg, can handle 2D and 3D vectors"""  
#    
#    def __init__(self, coord = (0,0)):
#        if coord.__len__() > 3: print "Can't create vector, pass a maximum of 3 coordinates!"
#        self.coord = coord
#
#    def __repr__(self):
#        return 'TwoD(%s)' % (*self.coord)
#
#    def __add__(self, other):
#        return TwoD(self.x + other.x, self.y + other.y)
#
#    def __sub__(self, other):
#        return TwoD(self.x - other.x, self.y - other.y)
#
#    def __mul__(self, other):
#        return TwoD(self.x * other, self.y * other)
#
#    def __div__(self, other):
#        return TwoD(self.x / other, self.y / other)
#
#    def __iadd__(self, other):
#        self.x += other.x
#        self.y += other.y
#        return self
#
#    def __isub__(self, other):
#        self.x -= other.x
#        self.y -= other.y
#        return self
#
#    def __idiv__(self, other):
#        self.x /= other
#        self.y /= other
#        return self
#    
#    def __imul__(self, other):
#        self.x /= other
#        self.y /= other
#        return self
#
#    def len(self):
#        '''length of vector'''
#        return ((self.x ** 2) + (self.y ** 2)) ** 0.5
#    
#    def set_len(self, len):
#        '''set length of vector'''
#        self = self.norm()*len
#    
#    def norm(self):
#        if self.len() == 0: return TwoD(0,0)
#        else: return self*(1./self.len())